package com.xayy.mgt.service.impl;

import cn.kawins.base.result.CheckResult;
import cn.kawins.base.utils.BeanUtil;
import cn.kawins.base.utils.CollUtil;
import cn.kawins.mybatis.base.BaseServiceImpl;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.xayy.mgt.mapper.AssociationParameterMapper;
import com.xayy.mgt.model.*;
import com.xayy.mgt.model.dto.NodeInfoDto;
import com.xayy.mgt.model.event.ParamUpdateEvent;
import com.xayy.mgt.model.vo.ParamVo;
import com.xayy.mgt.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class AssociationParameterServiceImpl extends BaseServiceImpl<AssociationParameter>
    implements AssociationParameterService {

//    @Autowired
//
//    private AssociationParameterService associationParameterService;

    @Resource
    private AssociationParameterMapper associationParameterMapper;

    @Autowired
    private PerformanceIndicatorsService performanceIndicatorsService;

    @Autowired
    private FunctionalIndicatorsService functionalIndicatorsService;

    @Autowired
    private NodeParamInfoService nodeParamInfoService;

    @Autowired
    private HealthDeepService healthDeepService;
    @Autowired
    private BridgeParamService bridgeParamService;
    @Autowired
    private NodeInfoService nodeInfoService;

    @Transactional
    @Override
    public CheckResult<Object> saveAssociationParameter(AssociationParameter associationParameter) {
        CheckResult<?> checkName = checkName(false, associationParameter);
        if (checkName.no()) {
            return CheckResult.fail(checkName.getCheckMsg());
        }
        CheckResult<?> checkCode = checkCode(false, associationParameter);
        if (checkCode.no()) {
            return CheckResult.fail(checkCode.getCheckMsg());
        }
        CheckResult<?> checkBug = checkBug(associationParameter);
        if (checkBug.no()) {
            return CheckResult.fail(checkBug.getCheckMsg());
        }
//        NodeTreeInfo nodeTreeInfo = nodeInfoService.selectById(associationParameter.getNodeId());
//        try {
//            CheckResult<?> checkSyntax = FunUtil.checkSyntax(nodeTreeInfo.getSatelliteId(), associationParameter.getParamNodeId(), new Date(), associationParameter.getCustomParam());
//            if (checkSyntax.no()) {
//                return CheckResult.fail(checkSyntax.getCheckMsg());
//            }
//        } catch (Exception e) {
//            return CheckResult.fail("自定义语法错误，请检查");
//        }
        this.insert(associationParameter);
        return CheckResult.success("新增成功");
    }

    @Override
    @Transactional
    public CheckResult<Object> deleteAssociationParameter(Long id) {
        this.deleteById(id);
        bridgeParamService.delete(BridgeParam.builder().childId(id).type(3).build());
        return CheckResult.success("删除成功");
    }

    @Override
    @Transactional
    public CheckResult<Object> deleteAssociationParameter(List<Long> ids) {
        this.deleteByIds(ids);
        Example example = new Example(BridgeParam.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("childId", ids);
        criteria.andIn("type", CollUtil.newArrayList(1, 2));
        bridgeParamService.deleteByExample(example);
        return CheckResult.success("删除成功");
    }

    @Override
    public CheckResult<Object> deleteByNodeId(Long id) {
        List<AssociationParameter> select = select(AssociationParameter.builder().nodeId(id).build());
        if (CollUtil.isNotEmpty(select)) {
            List<Long> ids = select.stream().map(AssociationParameter::getId).collect(Collectors.toList());
            return deleteAssociationParameter(ids);
        }
        return CheckResult.success();
    }

    @Override
    public CheckResult<Object> updateAssociationParameter(AssociationParameter associationParameter) {
        CheckResult<?> checkName = checkName(true, associationParameter);
        if (checkName.no()) {
            return CheckResult.fail(checkName.getCheckMsg());
        }
        CheckResult<?> checkCode = checkCode(true, associationParameter);
        if (checkCode.no()) {
            return CheckResult.fail(checkCode.getCheckMsg());
        }
//        CheckResult<?> checkBug = checkBug(associationParameter);
//        if (checkBug.no()) {
//            return CheckResult.fail(checkBug.getCheckMsg());
//        }
//        NodeTreeInfo nodeTreeInfo = nodeInfoService.selectById(associationParameter.getNodeId());
//        CheckResult<?> checkSyntax = FunUtil.checkSyntax(nodeTreeInfo.getSatelliteId(), associationParameter.getParamNodeId(), new Date(), associationParameter.getCustomParam());
//        if (checkSyntax.no()) {
//            return CheckResult.fail(checkSyntax.getCheckMsg());
//        }
        this.updateByIdSelective(associationParameter);
        return CheckResult.success("修改成功");
    }

    @Override

    public PageInfo<AssociationParameter> pageList(NodeInfoDto nodeInfoDto) {
        if (nodeInfoDto.getPage() == null || nodeInfoDto.getSize() == null) {
            Example example = new Example(AssociationParameter.class);
            example.createCriteria().andEqualTo("nodeId", nodeInfoDto.getParentId());
            List<AssociationParameter> associationParameterList = this.selectByExample(example);
            return new PageInfo<>(associationParameterList);
        }
        PageMethod.startPage(nodeInfoDto.getPage(), nodeInfoDto.getSize());
        List<AssociationParameter> associationParameterList = associationParameterMapper.pageList(nodeInfoDto);
        return new PageInfo<>(associationParameterList);
    }

    @Override
    public AssociationParameter getAssociationParameterDetail(Long associationParameterId) {
        return selectById(associationParameterId);

    }

    @Override
    public CheckResult<Object> getParamList(Integer type, Long nodeId) {
        List<ParamVo> paramVoList = new ArrayList<>();
        switch (type) {
            case 1: {
                CheckResult<List<NodeParamInfo>> params = nodeParamInfoService.getParams(nodeId);
                if (params.no())
                    return CheckResult.fail(params.getCheckMsg());
                List<NodeParamInfo> data = params.getData();
                data.forEach(x -> {
                    ParamVo paramVo = new ParamVo();
                    paramVo.setId(x.getId());
                    paramVo.setNodeId(nodeId);
                    paramVo.setParamName(x.getName());
                    paramVo.setParamCode(x.getCode());
                    paramVoList.add(paramVo);
                });
                break;
            }
            case 3: {
                CheckResult<List<PerformanceIndicators>> performanceIndicators =
                    performanceIndicatorsService.getPerformanceIndicators(nodeId);
                if (performanceIndicators.no())
                    return CheckResult.fail(performanceIndicators.getCheckMsg());
                List<PerformanceIndicators> data = performanceIndicators.getData();
                data.forEach(x -> {
                    ParamVo paramVo = new ParamVo();
                    paramVo.setId(x.getId());
                    paramVo.setNodeId(nodeId);
                    paramVo.setParamName(x.getMetricsName());
                    paramVo.setParamCode(x.getMetricsCode());
                    paramVoList.add(paramVo);
                });
                break;
            }
            case 2: {
                CheckResult<List<FunctionalIndicators>> functionalIndicators =
                    functionalIndicatorsService.getFunctionalIndicators(nodeId);
                if (functionalIndicators.no())
                    return CheckResult.fail(functionalIndicators.getCheckMsg());
                List<FunctionalIndicators> data = functionalIndicators.getData();
                data.forEach(x -> {
                    ParamVo paramVo = new ParamVo();
                    paramVo.setId(x.getId());
                    paramVo.setNodeId(nodeId);
                    paramVo.setParamName(x.getMetricsName());
                    paramVo.setParamCode(x.getMetricsCode());
                    paramVoList.add(paramVo);
                });
                break;
            }
            case 4: {
                CheckResult<HealthDeep> healthDeep = healthDeepService.getHealthDeep(nodeId);
                if (healthDeep.no())
                    return CheckResult.fail(healthDeep.getCheckMsg());
                HealthDeep data = healthDeep.getData();
                if (BeanUtil.isNotEmpty(data)) {
                    ParamVo paramVo = new ParamVo();
                    paramVo.setId(data.getId());
                    paramVo.setNodeId(nodeId);
                    paramVo.setParamName(data.getMetricsName());
                    paramVo.setParamCode(data.getMetricsCode());
                    paramVoList.add(paramVo);
                }
                break;
            }
            default: {
                return CheckResult.fail("参数类型不匹配");
            }
        }
        return CheckResult.success(paramVoList);
    }

    @EventListener
    public void handleParamUpdate(ParamUpdateEvent event) {
        AssociationParameter parameter = AssociationParameter.builder()
                .paramCode(event.getCode())
                .paramName(event.getName())
                .build();

        Example example = new Example(AssociationParameter.class);
        example.createCriteria().andEqualTo("nodeId", event.getNodeId());
        this.updateByExampleSelective(parameter, example);
    }

    /**
     * 校验同节点下得关联参数名称是否已存在
     *
     * @param isUpdate
     *            是否更新
     * @param associationParameter
     *            入参
     * @return 结果日志
     */
    private CheckResult<?> checkName(Boolean isUpdate, AssociationParameter associationParameter) {
        Example example = new Example(AssociationParameter.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("nodeId", associationParameter.getNodeId());
        criteria.andEqualTo("metricsName", associationParameter.getMetricsName());
        if (Boolean.TRUE.equals(isUpdate)) {
            criteria.andNotEqualTo("id", associationParameter.getId());
        }
        int i = selectCountByExample(example);
        if (i > 0) {
            return CheckResult.fail("指标名称：" + associationParameter.getMetricsName() + "已经存在");
        }
        return CheckResult.success();
    }

    /**
     * 校验同节点下得关联参数code是否已存在
     *
     * @param isUpdate
     *            是否更新
     * @param associationParameter
     *            入参
     * @return 结果日志
     */
    private CheckResult<?> checkCode(Boolean isUpdate, AssociationParameter associationParameter) {
        Example example = new Example(AssociationParameter.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("nodeId", associationParameter.getNodeId());
        criteria.andEqualTo("metricsCode", associationParameter.getMetricsCode());
        if (Boolean.TRUE.equals(isUpdate)) {
            criteria.andNotEqualTo("id", associationParameter.getId());
        }
        int i = selectCountByExample(example);
        if (i > 0) {
            return CheckResult.fail("指标代号：" + associationParameter.getMetricsCode() + "已经存在");
        }
        return CheckResult.success();
    }

    /**
     * 校验关联参数的选择的节点中是否有配置当前节点的指标为关联参数，防止死循环
     * 
     * @param associationParameter
     *            入参
     * @return 结果日志
     */
    private CheckResult<?> checkBug(AssociationParameter associationParameter) {
        Long nodeId = associationParameter.getNodeId();
        Long paramNodeId = associationParameter.getParamNodeId();
        if (nodeId.equals(paramNodeId)) {
            if (associationParameter.getType() != 1) {
                return CheckResult.fail("关联参数不能设置当前节点的功能指标、性能指标、健康度指标");
            }
            return CheckResult.success();
        }
        int i = selectCount(AssociationParameter.builder().nodeId(paramNodeId).paramNodeId(nodeId).build());
        if (i > 0) {
            return CheckResult.fail("被选择的节点已配置当前节点的指标项为关联参数，不支持相互设置");
        }
        return CheckResult.success();
    }

}
